import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:provider/provider.dart';
import 'package:awesome_notifications/awesome_notifications.dart';

void main() async {
  // Ensure Flutter is initialized
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize Awesome Notifications first
  await AwesomeNotifications().initialize(
    null, // no icon for now
    [
      NotificationChannel(
        channelKey: 'maintenance_channel',
        channelName: 'Maintenance Notifications',
        channelDescription: 'Notifications for maintenance reminders',
        defaultColor: Colors.blue,
        importance: NotificationImportance.High,
        channelShowBadge: true,
      )
    ],
  );

  // Listen for notification dismissal
  AwesomeNotifications().setListeners(
    onActionReceivedMethod: NotificationController.onActionReceivedMethod,
    onNotificationCreatedMethod:
        NotificationController.onNotificationCreatedMethod,
    onNotificationDisplayedMethod:
        NotificationController.onNotificationDisplayedMethod,
    onDismissActionReceivedMethod:
        NotificationController.onDismissActionReceivedMethod,
  );

  // Request permissions at startup
  await [
    Permission.bluetooth,
    Permission.bluetoothScan,
    Permission.bluetoothConnect,
    Permission.location,
    Permission.notification,
  ].request();

  // Initialize FlutterBluePlus
  FlutterBluePlus.setLogLevel(LogLevel.verbose, color: true);

  runApp(
    ChangeNotifierProvider(
      create: (_) => BleProvider(),
      child: const MyApp(),
    ),
  );
}

/// Notification controller to handle notification events
class NotificationController {
  /// Use this method to detect when a new notification is created
  @pragma("vm:entry-point")
  static Future<void> onNotificationCreatedMethod(
      ReceivedNotification receivedNotification) async {
    // Your code goes here
  }

  /// Use this method to detect every time that a new notification is displayed
  @pragma("vm:entry-point")
  static Future<void> onNotificationDisplayedMethod(
      ReceivedNotification receivedNotification) async {
    // Your code goes here
  }

  /// Use this method to detect if the user dismissed a notification
  @pragma("vm:entry-point")
  static Future<void> onDismissActionReceivedMethod(
      ReceivedAction receivedAction) async {
    // Clear the badge counter
    await AwesomeNotifications().decrementGlobalBadgeCounter();
  }

  /// Use this method to detect when the user taps on a notification or action button
  @pragma("vm:entry-point")
  static Future<void> onActionReceivedMethod(
      ReceivedAction receivedAction) async {
    // Clear the badge counter
    await AwesomeNotifications().decrementGlobalBadgeCounter();
  }
}

Future<void> scheduleMaintenanceNotification() async {
  bool isAllowed = await AwesomeNotifications().isNotificationAllowed();
  if (!isAllowed) {
    isAllowed =
        await AwesomeNotifications().requestPermissionToSendNotifications();
  }

  if (!isAllowed) {
    return;
  }

  await AwesomeNotifications().createNotification(
    content: NotificationContent(
      id: 1,
      channelKey: 'maintenance_channel',
      title: 'Time for Second Shot',
      body: 'Please continue the delivery process',
      notificationLayout: NotificationLayout.Default,
      wakeUpScreen: true,
      category: NotificationCategory.Reminder,
      badge: 1, // Set badge counter
    ),
    schedule: NotificationCalendar(
      second: DateTime.now().add(const Duration(seconds: 15)).second,
      minute: DateTime.now().minute,
      hour: DateTime.now().hour,
      day: DateTime.now().day,
      month: DateTime.now().month,
      year: DateTime.now().year,
      preciseAlarm: true,
      allowWhileIdle: true,
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: navigatorKey,
      title: 'ElectroVax',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ElectroVax'),
        actions: [
          IconButton(
            icon: const Icon(Icons.notification_add),
            onPressed: () async {
              // Test scheduled notification (5 seconds from now)
              await AwesomeNotifications().createNotification(
                content: NotificationContent(
                  id: 11,
                  channelKey: 'maintenance_channel',
                  title: 'Test Scheduled Notification',
                  body: 'This notification was scheduled for 5 seconds',
                ),
                schedule: NotificationInterval(
                  interval: 5,
                  repeats: false,
                ),
              );
              ScaffoldMessenger.of(context).showSnackBar(
                const SnackBar(
                  content: Text('Test notification scheduled for 5 seconds'),
                ),
              );
            },
          ),
        ],
      ),
      body: Consumer<BleProvider>(
        builder: (context, bleProvider, child) {
          // Show loading indicator while scanning
          if (bleProvider.isScanning) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }

          // Show device list if not connected
          if (bleProvider.connectedDevice == null) {
            return Column(
              children: [
                ElevatedButton(
                  onPressed: () => bleProvider.startScan(),
                  child: const Text('Start Scan'),
                ),
                Expanded(
                  child: ListView.builder(
                    itemCount: bleProvider.devices.length,
                    itemBuilder: (context, index) {
                      final device = bleProvider.devices[index];
                      return ListTile(
                        title: Text(device.name.isEmpty
                            ? 'Unknown Device'
                            : device.name),
                        subtitle: Text(device.id.id),
                        onTap: () => bleProvider.connectToDevice(device),
                      );
                    },
                  ),
                ),
              ],
            );
          }

          // Show connected device interface
          return Column(
            children: [
              Padding(
                padding: const EdgeInsets.all(8.0),
                child:
                    Text('Connected to: ${bleProvider.connectedDevice!.name}'),
              ),
              const CommandPanel(),
              Expanded(
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: PulseWidthGraph(),
                ),
              ),
              ElevatedButton(
                onPressed: () => bleProvider.disconnect(),
                child: const Text('Disconnect'),
              ),
              const SizedBox(height: 16),
            ],
          );
        },
      ),
    );
  }
}

class BleProvider extends ChangeNotifier {
  List<BluetoothDevice> devices = [];
  BluetoothDevice? connectedDevice;
  List<FlSpot> pulseData = [];
  bool isScanning = false;
  Color currentPulseColor = Colors.blue;

  // Add controllers for the text fields
  final pulseCountController = TextEditingController(text: '1');
  final pulseWidthController = TextEditingController(text: '100');
  final intervalController = TextEditingController(text: '1000');

  Timer? _timer;
  int _elapsedTime = 0;
  bool isRunning = false;
  String timerText = '0:00';

  @override
  void dispose() {
    pulseCountController.dispose();
    pulseWidthController.dispose();
    intervalController.dispose();
    _timer?.cancel();
    super.dispose();
  }

  Future<void> startScan() async {
    if (isScanning) return;

    // Request Bluetooth permissions
    Map<Permission, PermissionStatus> statuses = await [
      Permission.bluetooth,
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
      Permission.location,
    ].request();

    // Check if any permission was denied
    bool allGranted = true;
    statuses.forEach((permission, status) {
      if (!status.isGranted) {
        allGranted = false;
      }
    });

    if (!allGranted) {
      print('Bluetooth permissions not granted');
      return;
    }

    devices.clear();
    isScanning = true;
    notifyListeners();

    FlutterBluePlus.scanResults.listen((results) {
      for (ScanResult r in results) {
        // Only add devices that contain "micro" in their name (case insensitive)
        if (!devices.contains(r.device) &&
            r.device.name.toLowerCase().contains('micro')) {
          devices.add(r.device);
          notifyListeners();
        }
      }
    });

    await FlutterBluePlus.startScan(timeout: const Duration(seconds: 4));
    isScanning = false;
    notifyListeners();
  }

  Future<void> connectToDevice(BluetoothDevice device) async {
    try {
      await device.connect();
      connectedDevice = device;
      notifyListeners();
    } catch (e) {
      print('Error connecting to device: $e');
      // Show error to user
    }
  }

  void startTimer() {
    isRunning = true;
    _elapsedTime = 0;

    // Calculate total duration from pulse parameters
    int pulseCount = int.tryParse(pulseCountController.text) ?? 1;
    int interval = int.tryParse(intervalController.text) ?? 1000;
    int totalDuration = pulseCount * interval;

    _timer?.cancel();
    _timer = Timer.periodic(const Duration(milliseconds: 100), (timer) {
      _elapsedTime += 100;

      // Format timer text
      int seconds = _elapsedTime ~/ 1000;
      int milliseconds = (_elapsedTime % 1000) ~/ 10;
      timerText = '$seconds:${milliseconds.toString().padLeft(2, '0')}';

      // Stop timer when sequence is complete
      if (_elapsedTime >= totalDuration) {
        stopTimer();
      }
      notifyListeners();
    });
    notifyListeners();
  }

  void stopTimer() {
    isRunning = false;
    _timer?.cancel();
    _timer = null;
    notifyListeners();
  }

  void generatePulseData() {
    pulseData.clear();

    int pulseCount = 1; // Fixed to 1 pulse
    int pulseWidth = int.tryParse(pulseWidthController.text) ?? 100;
    int period = int.tryParse(intervalController.text) ?? 1000;

    // Ensure pulseWidth is not greater than period
    pulseWidth = pulseWidth.clamp(0, period);

    // Time scaling factor for better visualization (1 unit = 100ms)
    double timeScale = 100.0;

    // Calculate total time span needed
    double totalTimeSpan = (pulseCount * period) / timeScale;

    // For each pulse
    for (int i = 0; i < pulseCount; i++) {
      // Start time of this pulse
      double startTime = i * period / timeScale;

      // Add rising edge
      pulseData.add(FlSpot(startTime, 0));
      pulseData.add(FlSpot(startTime, 30)); // Fixed 30V

      // Add falling edge
      double fallTime = startTime + (pulseWidth / timeScale);
      pulseData.add(FlSpot(fallTime, 30)); // Fixed 30V
      pulseData.add(FlSpot(fallTime, 0));

      // Add end of period point if not last pulse
      if (i < pulseCount - 1) {
        double periodEnd = (i + 1) * period / timeScale;
        pulseData.add(FlSpot(periodEnd, 0));
      }
    }

    startTimer();
    notifyListeners();
  }

  Future<void> sendCommand(dynamic command) async {
    if (connectedDevice == null) return;

    try {
      List<BluetoothService> services =
          await connectedDevice!.discoverServices();
      for (var service in services) {
        for (var characteristic in service.characteristics) {
          if (characteristic.properties.write) {
            await characteristic.write([command]);
            if (command > 0) {
              currentPulseColor = command == 0x01 ? Colors.blue : Colors.green;
              generatePulseData();
              if (command == 0x01) {
                await scheduleMaintenanceNotification();
                showDialog(
                  context: navigatorKey.currentContext!,
                  builder: (context) => AlertDialog(
                    title: const Text('Reminder Set'),
                    content: const Text(
                      'A reminder for second shot has been set after 3 days',
                    ),
                    actions: [
                      TextButton(
                        onPressed: () => Navigator.pop(context),
                        child: const Text('OK'),
                      ),
                    ],
                  ),
                );
              }
            } else {
              stopTimer();
              timerText = '0:00';
              pulseData.clear();
              notifyListeners();
            }
            break;
          }
        }
      }
    } catch (e) {
      print('Error sending command: $e');
    }
  }

  void disconnect() async {
    if (connectedDevice != null) {
      await connectedDevice!.disconnect();
      connectedDevice = null;
      pulseData.clear();
      notifyListeners();
    }
  }
}

class CommandPanel extends StatelessWidget {
  const CommandPanel({super.key});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(8.0),
      child: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Consumer<BleProvider>(
              builder: (context, provider, child) {
                return Container(
                  constraints: const BoxConstraints(maxWidth: 600),
                  child: Column(
                    children: [
                      // Timer display
                      Container(
                        padding: const EdgeInsets.symmetric(
                            vertical: 8, horizontal: 12),
                        decoration: BoxDecoration(
                          border: Border.all(color: Colors.grey),
                          borderRadius: BorderRadius.circular(8),
                        ),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            const Icon(Icons.timer),
                            const SizedBox(width: 8),
                            Text(
                              provider.timerText,
                              style: const TextStyle(
                                fontSize: 20,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                          ],
                        ),
                      ),
                      const SizedBox(height: 16),
                      // Channel controls
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                        children: [
                          _buildChannelButton(
                            onPressed: () {
                              provider.pulseWidthController.text = '5';
                              provider.intervalController.text = '105';
                              context.read<BleProvider>().sendCommand(0x01);
                            },
                            text: 'Recruitment',
                            color: Colors.blue,
                          ),
                          _buildChannelButton(
                            onPressed: () {
                              provider.pulseWidthController.text = '20';
                              provider.intervalController.text = '120';
                              context.read<BleProvider>().sendCommand(0x02);
                            },
                            text: 'Delivery',
                            color: Colors.green,
                          ),
                          _buildChannelButton(
                            onPressed: () =>
                                context.read<BleProvider>().sendCommand(0x00),
                            text: 'ALL OFF',
                            color: Colors.red,
                          ),
                        ],
                      ),
                    ],
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildChannelButton({
    required VoidCallback onPressed,
    required String text,
    required Color color,
  }) {
    return ElevatedButton(
      onPressed: onPressed,
      style: ElevatedButton.styleFrom(
        backgroundColor: color,
        foregroundColor: Colors.white,
        minimumSize: const Size(120, 40),
      ),
      child: Text(text),
    );
  }
}

class PulseWidthGraph extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<BleProvider>(
      builder: (context, bleProvider, child) {
        // Calculate max X based on pulse data or default to 20
        double maxX = 10.0; // Default 1 second view
        if (bleProvider.pulseData.isNotEmpty) {
          maxX = bleProvider.pulseData.last.x;
          // Add 10% padding
          maxX += maxX * 0.1;
          // Round to next multiple of 10 for fewer labels
          maxX = (maxX / 10).ceil() * 10.0;
        }

        return LineChart(
          LineChartData(
            gridData: FlGridData(
              show: true,
              getDrawingHorizontalLine: (value) {
                return FlLine(
                  color: Colors.grey[300]!,
                  strokeWidth: 1,
                );
              },
              horizontalInterval: 10,
            ),
            titlesData: FlTitlesData(
              bottomTitles: AxisTitles(
                sideTitles: SideTitles(
                  showTitles: true,
                  reservedSize: 30,
                  interval: 10, // Show label every 10 units (1 second)
                  getTitlesWidget: (value, meta) {
                    // Only show labels at multiples of 10
                    if (value % 10 != 0) return const SizedBox.shrink();
                    // Convert to seconds if >= 10
                    if (value >= 10) {
                      return Text('${(value / 10).toInt()}s');
                    }
                    return Text('${(value * 100).toInt()}ms');
                  },
                ),
              ),
              leftTitles: AxisTitles(
                axisNameWidget: const Text('Voltage (V)'),
                sideTitles: SideTitles(
                  showTitles: true,
                  reservedSize: 40,
                  interval: 10, // Show voltage labels every 10V
                  getTitlesWidget: (value, meta) {
                    return Text('${value.toInt()}V');
                  },
                ),
              ),
              topTitles: const AxisTitles(
                sideTitles: SideTitles(showTitles: false),
              ),
              rightTitles: const AxisTitles(
                sideTitles: SideTitles(showTitles: false),
              ),
            ),
            borderData: FlBorderData(show: true),
            minX: 0,
            maxX: maxX,
            minY: -2,
            maxY: 40,
            clipData: FlClipData.all(),
            lineBarsData: [
              LineChartBarData(
                spots: bleProvider.pulseData,
                isCurved: false,
                color: bleProvider.currentPulseColor,
                barWidth: 2,
                dotData: const FlDotData(show: false),
                belowBarData: BarAreaData(show: false),
                preventCurveOverShooting: true,
              ),
            ],
          ),
        );
      },
    );
  }
}

// Add GlobalKey for accessing context
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
